This file is used to generate a dataset containing hair follicle stem cells (HFSCs), IBL and mORS. The goal is then to perform trajectory inference.

library(dplyr)
library(patchwork)
library(ggplot2)

.libPaths()
## [1] "/usr/local/lib/R/library"

Preparation

In this section, we set the global settings of the analysis. We will store data there :

save_name = "hfsc_iblmors"
out_dir = "."

We load the sample information :

sample_info = readRDS(paste0(out_dir, "/../../1_metadata/hs_hd_sample_info.rds"))
project_names_oi = sample_info$project_name

graphics::pie(rep(1, nrow(sample_info)),
              col = sample_info$color,
              labels = sample_info$project_name)

Here are custom colors for each cell type :

color_markers = readRDS(paste0(out_dir, "/../../1_metadata/hs_hd_color_markers.rds"))

data.frame(cell_type = names(color_markers),
           color = unlist(color_markers)) %>%
  ggplot2::ggplot(., aes(x = cell_type, y = 0, fill = cell_type)) +
  ggplot2::geom_point(pch = 21, size = 5) +
  ggplot2::scale_fill_manual(values = unlist(color_markers), breaks = names(color_markers)) +
  ggplot2::theme_classic() +
  ggplot2::theme(legend.position = "none",
                 axis.line = element_blank(),
                 axis.title = element_blank(),
                 axis.ticks = element_blank(),
                 axis.text.y = element_blank(),
                 axis.text.x = element_text(angle = 30, hjust = 1))

cell_type_oi = c("IBL", "ORS", "HFSC")
color_markers[!(names(color_markers) %in% cell_type_oi)] = "gray92"

Make hfsc_iblmors dataset

We build the dataset by combining the two HFSC and IBL/mORS datasets.

Load datasets

We load both datasets :

sobj_hfsc = readRDS(paste0(out_dir, "/../2_zoom_hfsc/hfsc_sobj.rds"))
sobj_hfsc
## An object of class Seurat 
## 15384 features across 1454 samples within 1 assay 
## Active assay: RNA (15384 features, 2000 variable features)
##  6 dimensional reductions calculated: RNA_pca, RNA_pca_24_tsne, RNA_pca_24_umap, harmony, harmony_24_umap, harmony_24_tsne
sobj_iblmors = readRDS(paste0(out_dir, "/../3_zoom_iblmors/iblmors_sobj.rds"))
sobj_iblmors
## An object of class Seurat 
## 16701 features across 3532 samples within 1 assay 
## Active assay: RNA (16701 features, 2000 variable features)
##  6 dimensional reductions calculated: RNA_pca, RNA_pca_20_tsne, RNA_pca_20_umap, harmony, harmony_20_umap, harmony_20_tsne

Do they have common metadata ?

setdiff(union(colnames(sobj_hfsc@meta.data), colnames(sobj_iblmors@meta.data)),
        intersect(colnames(sobj_hfsc@meta.data), colnames(sobj_iblmors@meta.data)))
## [1] "RNA_snn_res.0.5" "RNA_snn_res.1.7" "KRTDAP_expr"     "RNA_snn_res.1"

Except clustering-relative features, yes !

Combined dataset

We merge both objects :

sobj = merge(sobj_hfsc, sobj_iblmors)
sobj
## An object of class Seurat 
## 17050 features across 4986 samples within 1 assay 
## Active assay: RNA (17050 features, 0 variable features)

We delete them :

rm(sobj_hfsc, sobj_iblmors)

We remove all things that were calculated based on the full atlas :

sobj = Seurat::DietSeurat(sobj)
sobj
## An object of class Seurat 
## 17050 features across 4986 samples within 1 assay 
## Active assay: RNA (17050 features, 0 variable features)

Clean metadata

We keep a subset of meta.data and reset levels :

sobj@meta.data = sobj@meta.data[, c("orig.ident", "nCount_RNA", "nFeature_RNA", "log_nCount_RNA",
                                    "project_name", "sample_identifier", "sample_type", "cell_type",
                                    "Seurat.Phase", "cyclone.Phase", "percent.mt", "percent.rb")]

sobj$orig.ident = factor(sobj$orig.ident, levels = levels(sample_info$project_name))
sobj$project_name = factor(sobj$project_name, levels = levels(sample_info$project_name))
sobj$sample_identifier = factor(sobj$sample_identifier, levels = levels(sample_info$sample_identifier))
sobj$sample_type = factor(sobj$sample_type, levels = levels(sample_info$sample_type))

summary(sobj@meta.data)
##    orig.ident     nCount_RNA     nFeature_RNA  log_nCount_RNA    project_name 
##  2021_31: 419   Min.   :  691   Min.   : 498   Min.   : 6.540   2021_31: 419  
##  2021_36: 184   1st Qu.: 4057   1st Qu.:1340   1st Qu.: 8.308   2021_36: 184  
##  2021_41:1065   Median : 9348   Median :2615   Median : 9.143   2021_41:1065  
##  2022_03:1405   Mean   :11460   Mean   :2614   Mean   : 8.960   2022_03:1405  
##  2022_14: 986   3rd Qu.:15708   3rd Qu.:3628   3rd Qu.: 9.662   2022_14: 986  
##  2022_01: 353   Max.   :74961   Max.   :7109   Max.   :11.225   2022_01: 353  
##  2022_02: 574                                                   2022_02: 574  
##  sample_identifier sample_type  cell_type         Seurat.Phase      
##  HS_1: 419         HS:4059     Length:4986        Length:4986       
##  HS_2: 184         HD: 927     Class :character   Class :character  
##  HS_3:1065                     Mode  :character   Mode  :character  
##  HS_4:1405                                                          
##  HS_5: 986                                                          
##  HD_1: 353                                                          
##  HD_2: 574                                                          
##  cyclone.Phase        percent.mt       percent.rb     
##  Length:4986        Min.   : 0.000   Min.   : 0.4948  
##  Class :character   1st Qu.: 1.611   1st Qu.:21.4640  
##  Mode  :character   Median : 4.185   Median :26.2495  
##                     Mean   : 4.575   Mean   :25.4214  
##                     3rd Qu.: 6.168   3rd Qu.:30.7035  
##                     Max.   :19.826   Max.   :46.0169  
## 

Processing

Metadata

How many cells by sample ?

table(sobj$project_name)
## 
## 2021_31 2021_36 2021_41 2022_03 2022_14 2022_01 2022_02 
##     419     184    1065    1405     986     353     574

We represent this information as a barplot :

aquarius::plot_barplot(df = table(sobj$project_name,
                                  sobj$cell_type) %>%
                         as.data.frame.table() %>%
                         `colnames<-`(c("project_name", "cell_type", "nb_cells")),
                       x = "project_name", y = "nb_cells", fill = "cell_type",
                       position = position_stack()) +
  ggplot2::scale_fill_manual(values = color_markers,
                             breaks = names(color_markers),
                             name = "Cell type")

Projection

We remove genes that are expressed in less than 5 cells :

sobj = aquarius::filter_features(sobj, min_cells = 5)
## [1] 17050  4986
## [1] 17050  4986
sobj
## An object of class Seurat 
## 17050 features across 4986 samples within 1 assay 
## Active assay: RNA (17050 features, 0 variable features)

We normalize the count matrix for remaining cells :

sobj = Seurat::NormalizeData(sobj,
                             normalization.method = "LogNormalize")
sobj = Seurat::FindVariableFeatures(sobj, nfeatures = 2000)
sobj = Seurat::ScaleData(sobj)

sobj
## An object of class Seurat 
## 17050 features across 4986 samples within 1 assay 
## Active assay: RNA (17050 features, 2000 variable features)

We perform a PCA :

sobj = Seurat::RunPCA(sobj,
                      assay = "RNA",
                      reduction.name = "RNA_pca",
                      npcs = 100,
                      seed.use = 1337L)
sobj
## An object of class Seurat 
## 17050 features across 4986 samples within 1 assay 
## Active assay: RNA (17050 features, 2000 variable features)
##  1 dimensional reduction calculated: RNA_pca

We choose the number of dimensions such that they summarize 35 % of the variability :

stdev = sobj@reductions[["RNA_pca"]]@stdev
stdev_prop = cumsum(stdev)/sum(stdev)
ndims = which(stdev_prop > 0.35)[1]
ndims
## [1] 18

We can visualize this on the elbow plot :

elbow_p = Seurat::ElbowPlot(sobj, ndims = 100, reduction = "RNA_pca") +
  ggplot2::geom_point(x = ndims, y = stdev[ndims], col = "red")
x_text = ggplot_build(elbow_p)$layout$panel_params[[1]]$x$get_labels() %>% as.numeric()
elbow_p = elbow_p +
  ggplot2::scale_x_continuous(breaks = sort(c(x_text, ndims)), limits = c(0, 100))
x_color = ifelse(ggplot_build(elbow_p)$layout$panel_params[[1]]$x$get_labels() %>%
                   as.numeric() %>% round(., 2) == round(ndims, 2), "red", "black")
elbow_p = elbow_p +
  ggplot2::theme_classic() +
  ggplot2::theme(axis.text.x = element_text(color = x_color))

elbow_p

Without correction

We generate a tSNE and a UMAP with 18 principal components :

sobj = Seurat::RunTSNE(sobj,
                       reduction = "RNA_pca",
                       dims = 1:ndims,
                       seed.use = 1337L,
                       reduction.name = paste0("RNA_pca_", ndims, "_tsne"))

sobj = Seurat::RunUMAP(sobj,
                       reduction = "RNA_pca",
                       dims = 1:ndims,
                       seed.use = 1337L,
                       reduction.name = paste0("RNA_pca_", ndims, "_umap"))

We can visualize the two representations :

tsne = Seurat::DimPlot(sobj, group.by = "project_name",
                       reduction = paste0("RNA_pca_", ndims, "_tsne")) +
  ggplot2::scale_color_manual(values = sample_info$color,
                              breaks = sample_info$project_name) +
  Seurat::NoAxes() + ggplot2::ggtitle("PCA - tSNE") +
  ggplot2::theme(aspect.ratio = 1,
                 plot.title = element_text(hjust = 0.5),
                 legend.position = "none")

umap = Seurat::DimPlot(sobj, group.by = "project_name",
                       reduction = paste0("RNA_pca_", ndims, "_umap")) +
  ggplot2::scale_color_manual(values = sample_info$color,
                              breaks = sample_info$project_name) +
  Seurat::NoAxes() + ggplot2::ggtitle("PCA - UMAP") +
  ggplot2::theme(aspect.ratio = 1,
                 plot.title = element_text(hjust = 0.5))

tsne | umap

Harmony

We remove batch-effect using Harmony :

`%||%` = function(lhs, rhs) {
  if (!is.null(x = lhs)) {
    return(lhs)
  } else {
    return(rhs)
  }
}

set.seed(1337L)
sobj = harmony::RunHarmony(object = sobj,
                           group.by.vars = "project_name",
                           plot_convergence = TRUE,
                           reduction = "RNA_pca",
                           assay.use = "RNA",
                           reduction.save = "harmony",
                           max.iter.harmony = 20,
                           project.dim = FALSE)

From this batch-effect removed projection, we generate a tSNE and a UMAP.

sobj = Seurat::RunUMAP(sobj, 
                       seed.use = 1337L,
                       dims = 1:ndims,
                       reduction = "harmony",
                       reduction.name = paste0("harmony_", ndims, "_umap"),
                       reduction.key = paste0("harmony_", ndims, "umap_"))
sobj = Seurat::RunTSNE(sobj,
                       dims = 1:ndims,
                       seed.use = 1337L,
                       reduction = "harmony",
                       reduction.name = paste0("harmony_", ndims, "_tsne"),
                       reduction.key = paste0("harmony", ndims, "tsne_"))

These are the corrected UMAP and tSNE :

tsne = Seurat::DimPlot(sobj, group.by = "project_name",
                       reduction = paste0("harmony_", ndims, "_tsne")) +
  ggplot2::scale_color_manual(values = sample_info$color,
                              breaks = sample_info$project_name) +
  Seurat::NoAxes() + ggplot2::ggtitle("PCA - harmony - tSNE") +
  ggplot2::theme(aspect.ratio = 1,
                 plot.title = element_text(hjust = 0.5),
                 legend.position = "none")

umap = Seurat::DimPlot(sobj, group.by = "project_name",
                       reduction = paste0("harmony_", ndims, "_umap")) +
  ggplot2::scale_color_manual(values = sample_info$color,
                              breaks = sample_info$project_name) +
  Seurat::NoAxes() + ggplot2::ggtitle("PCA - harmony - UMAP") +
  ggplot2::theme(aspect.ratio = 1,
                 plot.title = element_text(hjust = 0.5))

tsne | umap

Diffusion map

We generate a diffusion map from the batch-effect corrected space :

sobj = aquarius::run_diffusion_map(sobj = sobj,
                                   input = "harmony",
                                   seed = 1337L,
                                   verbose = TRUE,
                                   n_eigs = 50,
                                   suppress_dpt = TRUE,
                                   return_dm = FALSE)
## finding knns......done. Time: 44.01s
## Calculating transition probabilities......done. Time: 1.91s
## 
## performing eigen decomposition......done. Time: 4.65s
dm_name = paste0("harmony_dm")

Seurat::DimPlot(sobj, reduction = dm_name,
                group.by = "cell_type", cols = color_markers) +
  ggplot2::labs(title = dm_name) +
  ggplot2::theme(aspect.ratio = 1,
                 plot.title = element_text(hjust = 0.5)) +
  Seurat::NoAxes()

We generate a UMAP from the diffusion map :

umap_dm_dims = 5
umap_name = paste0(dm_name, "_", umap_dm_dims, "_umap")

sobj = Seurat::RunUMAP(sobj, reduction = dm_name,
                       dims = 1:umap_dm_dims,
                       reduction.name = umap_name,
                       verbose = TRUE, seed.use = 1337L)

Seurat::DimPlot(sobj, reduction = umap_name,
                group.by = "cell_type", cols = color_markers) +
  ggplot2::labs(title = umap_name) +
  ggplot2::theme(aspect.ratio = 1,
                 plot.title = element_text(hjust = 0.5)) +
  Seurat::NoAxes()

We will keep the UMAP from DM :

reduction = "harmony"
name2D = umap_name

Clustering

We generate a clustering :

sobj = Seurat::FindNeighbors(sobj, reduction = reduction, dims = 1:ndims)
sobj = Seurat::FindClusters(sobj, resolution = 0.5)
## Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck
## 
## Number of nodes: 4986
## Number of edges: 189197
## 
## Running Louvain algorithm...
## Maximum modularity in 10 random starts: 0.8977
## Number of communities: 11
## Elapsed time: 0 seconds
dimplot_clusters = Seurat::DimPlot(sobj, reduction = name2D, label = TRUE) +
  Seurat::NoAxes() +
  ggplot2::theme(aspect.ratio = 1)
dimplot_clusters

Visualization

We can represent the 4 quality metrics :

plot_list = Seurat::FeaturePlot(sobj, reduction = name2D,
                                combine = FALSE, pt.size = 0.5,
                                features = c("percent.mt", "percent.rb", "nFeature_RNA", "log_nCount_RNA"))
plot_list = lapply(plot_list, FUN = function(one_plot) {
  one_plot +
    Seurat::NoAxes() +
    ggplot2::scale_color_gradientn(colors = aquarius:::color_gene) +
    ggplot2::theme(aspect.ratio = 1)
})

patchwork::wrap_plots(plot_list, nrow = 1)

We can visualize the two batch-effect corrected representations :

plot_list = lapply(c(paste0("harmony_", ndims, "_tsne"),
                     paste0("harmony_", ndims, "_umap"),
                     dm_name, umap_name),
                   FUN = function(one_proj) {
                       Seurat::DimPlot(sobj, group.by = "project_name",
                                       reduction = one_proj) +
                         ggplot2::scale_color_manual(values = sample_info$color,
                                                     breaks = sample_info$project_name) +
                         Seurat::NoAxes() + ggplot2::ggtitle(one_proj) +
                         ggplot2::theme(aspect.ratio = 1,
                                        plot.title = element_text(hjust = 0.5),
                                        legend.position = "none")
                     })

patchwork::wrap_plots(plot_list, ncol = 2)

Same figure colored by cell type :

plot_list = lapply(c(paste0("harmony_", ndims, "_tsne"),
                     paste0("harmony_", ndims, "_umap"),
                     dm_name, umap_name),
                   FUN = function(one_proj) {
                       Seurat::DimPlot(sobj, group.by = "cell_type",
                                       reduction = one_proj, cols = color_markers) +
                         Seurat::NoAxes() + ggplot2::ggtitle(one_proj) +
                         ggplot2::theme(aspect.ratio = 1,
                                        plot.title = element_text(hjust = 0.5),
                                        legend.position = "none")
                     })

patchwork::wrap_plots(plot_list, ncol = 2)

Same figure colored by clusters :

plot_list = lapply(c(paste0("harmony_", ndims, "_tsne"),
                     paste0("harmony_", ndims, "_umap"),
                     dm_name, umap_name),
                   FUN = function(one_proj) {
                       Seurat::DimPlot(sobj, group.by = "seurat_clusters", label = TRUE,
                                       reduction = one_proj) +
                         Seurat::NoAxes() + ggplot2::ggtitle(one_proj) +
                         ggplot2::theme(aspect.ratio = 1,
                                        plot.title = element_text(hjust = 0.5),
                                        legend.position = "none")
                     })

patchwork::wrap_plots(plot_list, ncol = 2)

Save

We save the Seurat object :

saveRDS(sobj, file = paste0(out_dir, "/", save_name, "_sobj.rds"))

R Session

show
## R version 3.6.3 (2020-02-29)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 20.04.6 LTS
## 
## Matrix products: default
## BLAS:   /usr/local/lib/R/lib/libRblas.so
## LAPACK: /usr/local/lib/R/lib/libRlapack.so
## 
## locale:
## [1] C
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
## [1] ggplot2_3.3.5   patchwork_1.1.2 dplyr_1.0.7    
## 
## loaded via a namespace (and not attached):
##   [1] softImpute_1.4              graphlayouts_0.7.0         
##   [3] pbapply_1.4-2               lattice_0.20-41            
##   [5] haven_2.3.1                 vctrs_0.3.8                
##   [7] usethis_2.0.1               dynwrap_1.2.1              
##   [9] blob_1.2.1                  survival_3.2-13            
##  [11] prodlim_2019.11.13          dynutils_1.0.5             
##  [13] later_1.3.0                 DBI_1.1.1                  
##  [15] R.utils_2.11.0              SingleCellExperiment_1.8.0 
##  [17] rappdirs_0.3.3              uwot_0.1.8                 
##  [19] dqrng_0.2.1                 jpeg_0.1-8.1               
##  [21] zlibbioc_1.32.0             pspline_1.0-18             
##  [23] pcaMethods_1.78.0           mvtnorm_1.1-1              
##  [25] htmlwidgets_1.5.4           GlobalOptions_0.1.2        
##  [27] future_1.22.1               UpSetR_1.4.0               
##  [29] laeken_0.5.2                leiden_0.3.3               
##  [31] clustree_0.4.3              parallel_3.6.3             
##  [33] scater_1.14.6               irlba_2.3.3                
##  [35] DEoptimR_1.0-9              tidygraph_1.1.2            
##  [37] Rcpp_1.0.9                  readr_2.0.2                
##  [39] KernSmooth_2.23-17          carrier_0.1.0              
##  [41] promises_1.1.0              gdata_2.18.0               
##  [43] DelayedArray_0.12.3         limma_3.42.2               
##  [45] graph_1.64.0                RcppParallel_5.1.4         
##  [47] Hmisc_4.4-0                 fs_1.5.2                   
##  [49] RSpectra_0.16-0             fastmatch_1.1-0            
##  [51] ranger_0.12.1               digest_0.6.25              
##  [53] png_0.1-7                   sctransform_0.2.1          
##  [55] cowplot_1.0.0               DOSE_3.12.0                
##  [57] here_1.0.1                  TInGa_0.0.0.9000           
##  [59] ggraph_2.0.3                pkgconfig_2.0.3            
##  [61] GO.db_3.10.0                DelayedMatrixStats_1.8.0   
##  [63] gower_0.2.1                 ggbeeswarm_0.6.0           
##  [65] iterators_1.0.12            DropletUtils_1.6.1         
##  [67] reticulate_1.26             clusterProfiler_3.14.3     
##  [69] SummarizedExperiment_1.16.1 circlize_0.4.15            
##  [71] beeswarm_0.4.0              GetoptLong_1.0.5           
##  [73] xfun_0.35                   bslib_0.3.1                
##  [75] zoo_1.8-10                  tidyselect_1.1.0           
##  [77] reshape2_1.4.4              purrr_0.3.4                
##  [79] ica_1.0-2                   pcaPP_1.9-73               
##  [81] viridisLite_0.3.0           rtracklayer_1.46.0         
##  [83] rlang_1.0.2                 hexbin_1.28.1              
##  [85] jquerylib_0.1.4             dyneval_0.9.9              
##  [87] glue_1.4.2                  RColorBrewer_1.1-2         
##  [89] matrixStats_0.56.0          stringr_1.4.0              
##  [91] lava_1.6.7                  europepmc_0.3              
##  [93] DESeq2_1.26.0               recipes_0.1.17             
##  [95] labeling_0.3                harmony_0.1.0              
##  [97] httpuv_1.5.2                class_7.3-17               
##  [99] BiocNeighbors_1.4.2         DO.db_2.9                  
## [101] annotate_1.64.0             jsonlite_1.7.2             
## [103] XVector_0.26.0              bit_4.0.4                  
## [105] mime_0.9                    aquarius_0.1.5             
## [107] Rsamtools_2.2.3             gridExtra_2.3              
## [109] gplots_3.0.3                stringi_1.4.6              
## [111] processx_3.5.2              gsl_2.1-6                  
## [113] bitops_1.0-6                cli_3.0.1                  
## [115] batchelor_1.2.4             RSQLite_2.2.0              
## [117] randomForest_4.6-14         tidyr_1.1.4                
## [119] data.table_1.14.2           rstudioapi_0.13            
## [121] org.Mm.eg.db_3.10.0         GenomicAlignments_1.22.1   
## [123] nlme_3.1-147                qvalue_2.18.0              
## [125] scran_1.14.6                locfit_1.5-9.4             
## [127] scDblFinder_1.1.8           listenv_0.8.0              
## [129] ggthemes_4.2.4              knn.covertree_1.0          
## [131] gridGraphics_0.5-0          R.oo_1.24.0                
## [133] dbplyr_1.4.4                BiocGenerics_0.32.0        
## [135] TTR_0.24.2                  readxl_1.3.1               
## [137] lifecycle_1.0.1             timeDate_3043.102          
## [139] ggpattern_0.3.1             munsell_0.5.0              
## [141] cellranger_1.1.0            R.methodsS3_1.8.1          
## [143] proxyC_0.1.5                visNetwork_2.0.9           
## [145] caTools_1.18.0              codetools_0.2-16           
## [147] Biobase_2.46.0              GenomeInfoDb_1.22.1        
## [149] vipor_0.4.5                 lmtest_0.9-38              
## [151] msigdbr_7.5.1               htmlTable_1.13.3           
## [153] triebeard_0.3.0             lsei_1.2-0                 
## [155] xtable_1.8-4                ROCR_1.0-7                 
## [157] BiocManager_1.30.10         scatterplot3d_0.3-41       
## [159] abind_1.4-5                 farver_2.0.3               
## [161] parallelly_1.28.1           RANN_2.6.1                 
## [163] askpass_1.1                 GenomicRanges_1.38.0       
## [165] RcppAnnoy_0.0.16            tibble_3.1.5               
## [167] ggdendro_0.1-20             cluster_2.1.0              
## [169] future.apply_1.5.0          Seurat_3.1.5               
## [171] dendextend_1.15.1           Matrix_1.3-2               
## [173] ellipsis_0.3.2              prettyunits_1.1.1          
## [175] lubridate_1.7.9             ggridges_0.5.2             
## [177] igraph_1.2.5                RcppEigen_0.3.3.7.0        
## [179] fgsea_1.12.0                remotes_2.4.2              
## [181] scBFA_1.0.0                 destiny_3.0.1              
## [183] VIM_6.1.1                   testthat_3.1.0             
## [185] htmltools_0.5.2             BiocFileCache_1.10.2       
## [187] yaml_2.2.1                  utf8_1.1.4                 
## [189] plotly_4.9.2.1              XML_3.99-0.3               
## [191] ModelMetrics_1.2.2.2        e1071_1.7-3                
## [193] foreign_0.8-76              withr_2.5.0                
## [195] fitdistrplus_1.0-14         BiocParallel_1.20.1        
## [197] xgboost_1.4.1.1             bit64_4.0.5                
## [199] foreach_1.5.0               robustbase_0.93-9          
## [201] Biostrings_2.54.0           GOSemSim_2.13.1            
## [203] rsvd_1.0.3                  memoise_2.0.0              
## [205] evaluate_0.18               forcats_0.5.0              
## [207] rio_0.5.16                  geneplotter_1.64.0         
## [209] tzdb_0.1.2                  caret_6.0-86               
## [211] ps_1.6.0                    DiagrammeR_1.0.6.1         
## [213] curl_4.3                    fdrtool_1.2.15             
## [215] fansi_0.4.1                 highr_0.8                  
## [217] urltools_1.7.3              xts_0.12.1                 
## [219] GSEABase_1.48.0             acepack_1.4.1              
## [221] edgeR_3.28.1                checkmate_2.0.0            
## [223] scds_1.2.0                  cachem_1.0.6               
## [225] npsurv_0.4-0                babelgene_22.3             
## [227] rjson_0.2.20                openxlsx_4.1.5             
## [229] ggrepel_0.9.1               clue_0.3-60                
## [231] rprojroot_2.0.2             stabledist_0.7-1           
## [233] tools_3.6.3                 sass_0.4.0                 
## [235] nichenetr_1.1.1             magrittr_2.0.1             
## [237] RCurl_1.98-1.2              proxy_0.4-24               
## [239] car_3.0-11                  ape_5.3                    
## [241] ggplotify_0.0.5             xml2_1.3.2                 
## [243] httr_1.4.2                  assertthat_0.2.1           
## [245] rmarkdown_2.18              boot_1.3-25                
## [247] globals_0.14.0              R6_2.4.1                   
## [249] Rhdf5lib_1.8.0              nnet_7.3-14                
## [251] RcppHNSW_0.2.0              progress_1.2.2             
## [253] genefilter_1.68.0           statmod_1.4.34             
## [255] gtools_3.8.2                shape_1.4.6                
## [257] HDF5Array_1.14.4            BiocSingular_1.2.2         
## [259] rhdf5_2.30.1                splines_3.6.3              
## [261] AUCell_1.8.0                carData_3.0-4              
## [263] colorspace_1.4-1            generics_0.1.0             
## [265] stats4_3.6.3                base64enc_0.1-3            
## [267] dynfeature_1.0.0            smoother_1.1               
## [269] gridtext_0.1.1              pillar_1.6.3               
## [271] tweenr_1.0.1                sp_1.4-1                   
## [273] ggplot.multistats_1.0.0     rvcheck_0.1.8              
## [275] GenomeInfoDbData_1.2.2      plyr_1.8.6                 
## [277] gtable_0.3.0                zip_2.2.0                  
## [279] knitr_1.41                  ComplexHeatmap_2.14.0      
## [281] latticeExtra_0.6-29         biomaRt_2.42.1             
## [283] IRanges_2.20.2              fastmap_1.1.0              
## [285] ADGofTest_0.3               copula_1.0-0               
## [287] doParallel_1.0.15           AnnotationDbi_1.48.0       
## [289] vcd_1.4-8                   babelwhale_1.0.1           
## [291] openssl_1.4.1               scales_1.1.1               
## [293] backports_1.2.1             S4Vectors_0.24.4           
## [295] ipred_0.9-12                enrichplot_1.6.1           
## [297] hms_1.1.1                   ggforce_0.3.1              
## [299] Rtsne_0.15                  shiny_1.7.1                
## [301] numDeriv_2016.8-1.1         polyclip_1.10-0            
## [303] grid_3.6.3                  lazyeval_0.2.2             
## [305] Formula_1.2-3               tsne_0.1-3                 
## [307] crayon_1.3.4                MASS_7.3-54                
## [309] pROC_1.16.2                 viridis_0.5.1              
## [311] dynparam_1.0.0              rpart_4.1-15               
## [313] zinbwave_1.8.0              compiler_3.6.3             
## [315] ggtext_0.1.0
LS0tCnRpdGxlOiAiSFMgcHJvamVjdCIKc3VidGl0bGU6ICJab29tIGluIEhGU0NzICsgSUJMICsgbU9SUyIKYXV0aG9yOiAiQXVkcmV5IgpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclWS0lbS0lZCcpYCIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IGZhbHNlCi0tLQoKPHN0eWxlPgpib2R5IHsKdGV4dC1hbGlnbjoganVzdGlmeX0KPC9zdHlsZT4KCjwhLS0gQXV0b21hdGljYWxseSBjb21wdXRlcyBhbmQgcHJpbnRzIGluIHRoZSBvdXRwdXQgdGhlIHJ1bm5pbmcgdGltZSBmb3IgYW55IGNvZGUgY2h1bmsgLS0+CmBgYHtyLCBlY2hvPUZBTFNFfQojIGh0dHBzOi8vZ2l0aHViLmNvbS9yc3R1ZGlvL3JtYXJrZG93bi9pc3N1ZXMvMTQ1Mwpob29rcyA9IGtuaXRyOjprbml0X2hvb2tzJGdldCgpCmhvb2tfZm9sZGFibGUgPSBmdW5jdGlvbih0eXBlKSB7CiAgZm9yY2UodHlwZSkKICBmdW5jdGlvbih4LCBvcHRpb25zKSB7CiAgICByZXMgPSBob29rc1tbdHlwZV1dKHgsIG9wdGlvbnMpCiAgICAKICAgIGlmIChpc0ZBTFNFKG9wdGlvbnNbW3Bhc3RlMCgiZm9sZF8iLCB0eXBlKV1dKSkgcmV0dXJuKHJlcykKICAgIAogICAgcGFzdGUwKAogICAgICAiPGRldGFpbHM+PHN1bW1hcnk+IiwgInNob3ciLCAiPC9zdW1tYXJ5PlxuXG4iLAogICAgICByZXMsCiAgICAgICJcblxuPC9kZXRhaWxzPiIKICAgICkKICB9Cn0Ka25pdHI6OmtuaXRfaG9va3Mkc2V0KAogIG91dHB1dCA9IGhvb2tfZm9sZGFibGUoIm91dHB1dCIpLAogIHBsb3QgPSBob29rX2ZvbGRhYmxlKCJwbG90IiksCiAgdGltZV9pdCA9IGxvY2FsKHsKICAgIG5vdyA9IE5VTEwKICAgIGZ1bmN0aW9uKGJlZm9yZSwgb3B0aW9ucykgewogICAgICBpZiAob3B0aW9ucyR0aW1lX2l0KSB7CiAgICAgICAgaWYgKGJlZm9yZSkgewogICAgICAgICAgbm93IDw9IFN5cy50aW1lKCkKICAgICAgICB9IGVsc2UgewogICAgICAgICAgcmVzID0gZGlmZnRpbWUoU3lzLnRpbWUoKSwgbm93LCB1bml0cyA9ICJzZWNzIikKICAgICAgICAgIHBhc3RlKCIoVGltZSB0byBydW4gOiIsIHJvdW5kKHJlcywgZGlnaXRzID0gMiksICJzKSIpCiAgICAgICAgfQogICAgICB9CiAgICB9CiAgfSkKKQpgYGAKCjwhLS0gU2V0IGRlZmF1bHQgcGFyYW1ldGVycyBmb3IgYWxsIGNodW5rcyAtLT4KYGBge3IsIHNldHVwLCBpbmNsdWRlID0gRkFMU0V9CnNldC5zZWVkKDEzMzdMKQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsICMgZGlzcGxheSBjb2RlCiAgICAgICAgICAgICAgICAgICAgICAjIGRpc3BsYXkgY2h1bmsgb3V0cHV0CiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICBmb2xkX291dHB1dCA9IEZBTFNFLCAjIHVzZWZ1bGwgZm9yIHNlc3Npb25JbmZvKCkKICAgICAgICAgICAgICAgICAgICAgIGZvbGRfcGxvdCA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAjIGZpZ3VyZSBzZXR0aW5ncwogICAgICAgICAgICAgICAgICAgICAgZmlnLmFsaWduID0gJ2NlbnRlcicsCiAgICAgICAgICAgICAgICAgICAgICBmaWcud2lkdGggPSAyMCwKICAgICAgICAgICAgICAgICAgICAgIGZpZy5oZWlnaHQgPSAxNSwKICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgIyBzb21ldGhpbmcgYWJvdXQgc2VlZCwgY2h1bmsgYW5kIFJtYXJrZG93biBjb21waWxhdGlvbgogICAgICAgICAgICAgICAgICAgICAgIyBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy8zOTQxNzAwMy9sb25nLXZlY3RvcnMtbm90LXN1cHBvcnRlZC15ZXQtZXJyb3ItaW4tcm1kLWJ1dC1ub3QtaW4tci1zY3JpcHQKICAgICAgICAgICAgICAgICAgICAgICMgY2FjaGUgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgY2FjaGUubGF6eSA9IEZBTFNFLCAKICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgIyBhZGQgcnVudGltZSBhZnRlciBjaHVuawogICAgICAgICAgICAgICAgICAgICAgdGltZV9pdCA9IEZBTFNFKQpgYGAKCgpUaGlzIGZpbGUgaXMgdXNlZCB0byBnZW5lcmF0ZSBhIGRhdGFzZXQgY29udGFpbmluZyBoYWlyIGZvbGxpY2xlIHN0ZW0gY2VsbHMgKEhGU0NzKSwgSUJMIGFuZCBtT1JTLiBUaGUgZ29hbCBpcyB0aGVuIHRvIHBlcmZvcm0gdHJhamVjdG9yeSBpbmZlcmVuY2UuCgpgYGB7ciBsaWJyYXJ5fQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHBhdGNod29yaykKbGlicmFyeShnZ3Bsb3QyKQoKLmxpYlBhdGhzKCkKYGBgCgoKIyBQcmVwYXJhdGlvbgoKSW4gdGhpcyBzZWN0aW9uLCB3ZSBzZXQgdGhlIGdsb2JhbCBzZXR0aW5ncyBvZiB0aGUgYW5hbHlzaXMuIFdlIHdpbGwgc3RvcmUgZGF0YSB0aGVyZSA6CgpgYGB7ciBvdXRfZGlyfQpzYXZlX25hbWUgPSAiaGZzY19pYmxtb3JzIgpvdXRfZGlyID0gIi4iCmBgYAoKV2UgbG9hZCB0aGUgc2FtcGxlIGluZm9ybWF0aW9uIDoKCmBgYHtyIGN1c3RvbV9wYWxldHRlX3NhbXBsZSwgZmlnLndpZHRoID0gNiwgZmlnLmhlaWdodCA9IDZ9CnNhbXBsZV9pbmZvID0gcmVhZFJEUyhwYXN0ZTAob3V0X2RpciwgIi8uLi8uLi8xX21ldGFkYXRhL2hzX2hkX3NhbXBsZV9pbmZvLnJkcyIpKQpwcm9qZWN0X25hbWVzX29pID0gc2FtcGxlX2luZm8kcHJvamVjdF9uYW1lCgpncmFwaGljczo6cGllKHJlcCgxLCBucm93KHNhbXBsZV9pbmZvKSksCiAgICAgICAgICAgICAgY29sID0gc2FtcGxlX2luZm8kY29sb3IsCiAgICAgICAgICAgICAgbGFiZWxzID0gc2FtcGxlX2luZm8kcHJvamVjdF9uYW1lKQpgYGAKCkhlcmUgYXJlIGN1c3RvbSBjb2xvcnMgZm9yIGVhY2ggY2VsbCB0eXBlIDoKCmBgYHtyIGNvbG9yX21hcmtlcnMsIGZpZy53aWR0aCA9IDEwLCBmaWcuaGVpZ2h0ID0gMSwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CmNvbG9yX21hcmtlcnMgPSByZWFkUkRTKHBhc3RlMChvdXRfZGlyLCAiLy4uLy4uLzFfbWV0YWRhdGEvaHNfaGRfY29sb3JfbWFya2Vycy5yZHMiKSkKCmRhdGEuZnJhbWUoY2VsbF90eXBlID0gbmFtZXMoY29sb3JfbWFya2VycyksCiAgICAgICAgICAgY29sb3IgPSB1bmxpc3QoY29sb3JfbWFya2VycykpICU+JQogIGdncGxvdDI6OmdncGxvdCguLCBhZXMoeCA9IGNlbGxfdHlwZSwgeSA9IDAsIGZpbGwgPSBjZWxsX3R5cGUpKSArCiAgZ2dwbG90Mjo6Z2VvbV9wb2ludChwY2ggPSAyMSwgc2l6ZSA9IDUpICsKICBnZ3Bsb3QyOjpzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSB1bmxpc3QoY29sb3JfbWFya2VycyksIGJyZWFrcyA9IG5hbWVzKGNvbG9yX21hcmtlcnMpKSArCiAgZ2dwbG90Mjo6dGhlbWVfY2xhc3NpYygpICsKICBnZ3Bsb3QyOjp0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgICAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDMwLCBoanVzdCA9IDEpKQpgYGAKCmBgYHtyIHN1YnNldF9jb2xvcl9tYXJrZXJzfQpjZWxsX3R5cGVfb2kgPSBjKCJJQkwiLCAiT1JTIiwgIkhGU0MiKQpjb2xvcl9tYXJrZXJzWyEobmFtZXMoY29sb3JfbWFya2VycykgJWluJSBjZWxsX3R5cGVfb2kpXSA9ICJncmF5OTIiCmBgYAoKCiMgTWFrZSBgciBzYXZlX25hbWVgIGRhdGFzZXQKCldlIGJ1aWxkIHRoZSBkYXRhc2V0IGJ5IGNvbWJpbmluZyB0aGUgdHdvIEhGU0MgYW5kIElCTC9tT1JTIGRhdGFzZXRzLgoKIyMgTG9hZCBkYXRhc2V0cwoKV2UgbG9hZCBib3RoIGRhdGFzZXRzIDoKCmBgYHtyIGxvYWRfem9vbWVkfQpzb2JqX2hmc2MgPSByZWFkUkRTKHBhc3RlMChvdXRfZGlyLCAiLy4uLzJfem9vbV9oZnNjL2hmc2Nfc29iai5yZHMiKSkKc29ial9oZnNjCgpzb2JqX2libG1vcnMgPSByZWFkUkRTKHBhc3RlMChvdXRfZGlyLCAiLy4uLzNfem9vbV9pYmxtb3JzL2libG1vcnNfc29iai5yZHMiKSkKc29ial9pYmxtb3JzCmBgYAoKRG8gdGhleSBoYXZlIGNvbW1vbiBtZXRhZGF0YSA/CgpgYGB7ciBzYW1lX21ldGFkYXRhfQpzZXRkaWZmKHVuaW9uKGNvbG5hbWVzKHNvYmpfaGZzY0BtZXRhLmRhdGEpLCBjb2xuYW1lcyhzb2JqX2libG1vcnNAbWV0YS5kYXRhKSksCiAgICAgICAgaW50ZXJzZWN0KGNvbG5hbWVzKHNvYmpfaGZzY0BtZXRhLmRhdGEpLCBjb2xuYW1lcyhzb2JqX2libG1vcnNAbWV0YS5kYXRhKSkpCmBgYAoKRXhjZXB0IGNsdXN0ZXJpbmctcmVsYXRpdmUgZmVhdHVyZXMsIHllcyAhCgojIyBDb21iaW5lZCBkYXRhc2V0CgpXZSBtZXJnZSBib3RoIG9iamVjdHMgOgoKYGBge3IgbWVyZ2Vfc29ian0Kc29iaiA9IG1lcmdlKHNvYmpfaGZzYywgc29ial9pYmxtb3JzKQpzb2JqCmBgYAoKV2UgZGVsZXRlIHRoZW0gOgoKYGBge3IgY2xlYW5fc29ian0Kcm0oc29ial9oZnNjLCBzb2JqX2libG1vcnMpCmBgYAoKV2UgcmVtb3ZlIGFsbCB0aGluZ3MgdGhhdCB3ZXJlIGNhbGN1bGF0ZWQgYmFzZWQgb24gdGhlIGZ1bGwgYXRsYXMgOgoKYGBge3IgcmVtb3ZlX3JlZHVjdGlvbnN9CnNvYmogPSBTZXVyYXQ6OkRpZXRTZXVyYXQoc29iaikKc29iagpgYGAKCiMjIENsZWFuIG1ldGFkYXRhCgpXZSBrZWVwIGEgc3Vic2V0IG9mIG1ldGEuZGF0YSBhbmQgcmVzZXQgbGV2ZWxzIDoKCmBgYHtyIHNvYmpfc2V0X2ZhY3Rvcl9sZXZlbHN9CnNvYmpAbWV0YS5kYXRhID0gc29iakBtZXRhLmRhdGFbLCBjKCJvcmlnLmlkZW50IiwgIm5Db3VudF9STkEiLCAibkZlYXR1cmVfUk5BIiwgImxvZ19uQ291bnRfUk5BIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInByb2plY3RfbmFtZSIsICJzYW1wbGVfaWRlbnRpZmllciIsICJzYW1wbGVfdHlwZSIsICJjZWxsX3R5cGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU2V1cmF0LlBoYXNlIiwgImN5Y2xvbmUuUGhhc2UiLCAicGVyY2VudC5tdCIsICJwZXJjZW50LnJiIildCgpzb2JqJG9yaWcuaWRlbnQgPSBmYWN0b3Ioc29iaiRvcmlnLmlkZW50LCBsZXZlbHMgPSBsZXZlbHMoc2FtcGxlX2luZm8kcHJvamVjdF9uYW1lKSkKc29iaiRwcm9qZWN0X25hbWUgPSBmYWN0b3Ioc29iaiRwcm9qZWN0X25hbWUsIGxldmVscyA9IGxldmVscyhzYW1wbGVfaW5mbyRwcm9qZWN0X25hbWUpKQpzb2JqJHNhbXBsZV9pZGVudGlmaWVyID0gZmFjdG9yKHNvYmokc2FtcGxlX2lkZW50aWZpZXIsIGxldmVscyA9IGxldmVscyhzYW1wbGVfaW5mbyRzYW1wbGVfaWRlbnRpZmllcikpCnNvYmokc2FtcGxlX3R5cGUgPSBmYWN0b3Ioc29iaiRzYW1wbGVfdHlwZSwgbGV2ZWxzID0gbGV2ZWxzKHNhbXBsZV9pbmZvJHNhbXBsZV90eXBlKSkKCnN1bW1hcnkoc29iakBtZXRhLmRhdGEpCmBgYAoKIyBQcm9jZXNzaW5nCgojIyBNZXRhZGF0YQoKSG93IG1hbnkgY2VsbHMgYnkgc2FtcGxlID8KCmBgYHtyIHRhYmxlX29yaWdfaWRlbnR9CnRhYmxlKHNvYmokcHJvamVjdF9uYW1lKQpgYGAKCldlIHJlcHJlc2VudCB0aGlzIGluZm9ybWF0aW9uIGFzIGEgYmFycGxvdCA6CgpgYGB7ciBiYXJwbG90X2NvdW50LCBmaWcud2lkdGggPSA4LCBmaWcuaGVpZ2h0ID0gNX0KYXF1YXJpdXM6OnBsb3RfYmFycGxvdChkZiA9IHRhYmxlKHNvYmokcHJvamVjdF9uYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc29iaiRjZWxsX3R5cGUpICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgYXMuZGF0YS5mcmFtZS50YWJsZSgpICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgYGNvbG5hbWVzPC1gKGMoInByb2plY3RfbmFtZSIsICJjZWxsX3R5cGUiLCAibmJfY2VsbHMiKSksCiAgICAgICAgICAgICAgICAgICAgICAgeCA9ICJwcm9qZWN0X25hbWUiLCB5ID0gIm5iX2NlbGxzIiwgZmlsbCA9ICJjZWxsX3R5cGUiLAogICAgICAgICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2soKSkgKwogIGdncGxvdDI6OnNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbG9yX21hcmtlcnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gbmFtZXMoY29sb3JfbWFya2VycyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICJDZWxsIHR5cGUiKQpgYGAKCiMjIFByb2plY3Rpb24KCldlIHJlbW92ZSBnZW5lcyB0aGF0IGFyZSBleHByZXNzZWQgaW4gbGVzcyB0aGFuIDUgY2VsbHMgOgoKYGBge3IgZmlsdGVyX2dlbmVzfQpzb2JqID0gYXF1YXJpdXM6OmZpbHRlcl9mZWF0dXJlcyhzb2JqLCBtaW5fY2VsbHMgPSA1KQpzb2JqCmBgYAoKCldlIG5vcm1hbGl6ZSB0aGUgY291bnQgbWF0cml4IGZvciByZW1haW5pbmcgY2VsbHMgOgoKYGBge3Igbm9ybWFsaXphdGlvbjJ9CnNvYmogPSBTZXVyYXQ6Ok5vcm1hbGl6ZURhdGEoc29iaiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBub3JtYWxpemF0aW9uLm1ldGhvZCA9ICJMb2dOb3JtYWxpemUiKQpzb2JqID0gU2V1cmF0OjpGaW5kVmFyaWFibGVGZWF0dXJlcyhzb2JqLCBuZmVhdHVyZXMgPSAyMDAwKQpzb2JqID0gU2V1cmF0OjpTY2FsZURhdGEoc29iaikKCnNvYmoKYGBgCgpXZSBwZXJmb3JtIGEgUENBIDoKCmBgYHtyIHBjYTJ9CnNvYmogPSBTZXVyYXQ6OlJ1blBDQShzb2JqLAogICAgICAgICAgICAgICAgICAgICAgYXNzYXkgPSAiUk5BIiwKICAgICAgICAgICAgICAgICAgICAgIHJlZHVjdGlvbi5uYW1lID0gIlJOQV9wY2EiLAogICAgICAgICAgICAgICAgICAgICAgbnBjcyA9IDEwMCwKICAgICAgICAgICAgICAgICAgICAgIHNlZWQudXNlID0gMTMzN0wpCnNvYmoKYGBgCgpXZSBjaG9vc2UgdGhlIG51bWJlciBvZiBkaW1lbnNpb25zIHN1Y2ggdGhhdCB0aGV5IHN1bW1hcml6ZSAzNSAlIG9mIHRoZSB2YXJpYWJpbGl0eSA6CgpgYGB7ciBuZGltczJ9CnN0ZGV2ID0gc29iakByZWR1Y3Rpb25zW1siUk5BX3BjYSJdXUBzdGRldgpzdGRldl9wcm9wID0gY3Vtc3VtKHN0ZGV2KS9zdW0oc3RkZXYpCm5kaW1zID0gd2hpY2goc3RkZXZfcHJvcCA+IDAuMzUpWzFdCm5kaW1zCmBgYAoKV2UgY2FuIHZpc3VhbGl6ZSB0aGlzIG9uIHRoZSBlbGJvdyBwbG90IDoKCmBgYHtyIGVsYm93cGxvdDIsIGZpZy53aWR0aCA9IDEyLCBmaWcuaGVpZ2h0ID0gNH0KZWxib3dfcCA9IFNldXJhdDo6RWxib3dQbG90KHNvYmosIG5kaW1zID0gMTAwLCByZWR1Y3Rpb24gPSAiUk5BX3BjYSIpICsKICBnZ3Bsb3QyOjpnZW9tX3BvaW50KHggPSBuZGltcywgeSA9IHN0ZGV2W25kaW1zXSwgY29sID0gInJlZCIpCnhfdGV4dCA9IGdncGxvdF9idWlsZChlbGJvd19wKSRsYXlvdXQkcGFuZWxfcGFyYW1zW1sxXV0keCRnZXRfbGFiZWxzKCkgJT4lIGFzLm51bWVyaWMoKQplbGJvd19wID0gZWxib3dfcCArCiAgZ2dwbG90Mjo6c2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNvcnQoYyh4X3RleHQsIG5kaW1zKSksIGxpbWl0cyA9IGMoMCwgMTAwKSkKeF9jb2xvciA9IGlmZWxzZShnZ3Bsb3RfYnVpbGQoZWxib3dfcCkkbGF5b3V0JHBhbmVsX3BhcmFtc1tbMV1dJHgkZ2V0X2xhYmVscygpICU+JQogICAgICAgICAgICAgICAgICAgYXMubnVtZXJpYygpICU+JSByb3VuZCguLCAyKSA9PSByb3VuZChuZGltcywgMiksICJyZWQiLCAiYmxhY2siKQplbGJvd19wID0gZWxib3dfcCArCiAgZ2dwbG90Mjo6dGhlbWVfY2xhc3NpYygpICsKICBnZ3Bsb3QyOjp0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChjb2xvciA9IHhfY29sb3IpKQoKZWxib3dfcApgYGAKCiMjIyBXaXRob3V0IGNvcnJlY3Rpb24KCldlIGdlbmVyYXRlIGEgdFNORSBhbmQgYSBVTUFQIHdpdGggYHIgbmRpbXNgIHByaW5jaXBhbCBjb21wb25lbnRzIDoKCmBgYHtyIHRzbmVfdW1hcDJ9CnNvYmogPSBTZXVyYXQ6OlJ1blRTTkUoc29iaiwKICAgICAgICAgICAgICAgICAgICAgICByZWR1Y3Rpb24gPSAiUk5BX3BjYSIsCiAgICAgICAgICAgICAgICAgICAgICAgZGltcyA9IDE6bmRpbXMsCiAgICAgICAgICAgICAgICAgICAgICAgc2VlZC51c2UgPSAxMzM3TCwKICAgICAgICAgICAgICAgICAgICAgICByZWR1Y3Rpb24ubmFtZSA9IHBhc3RlMCgiUk5BX3BjYV8iLCBuZGltcywgIl90c25lIikpCgpzb2JqID0gU2V1cmF0OjpSdW5VTUFQKHNvYmosCiAgICAgICAgICAgICAgICAgICAgICAgcmVkdWN0aW9uID0gIlJOQV9wY2EiLAogICAgICAgICAgICAgICAgICAgICAgIGRpbXMgPSAxOm5kaW1zLAogICAgICAgICAgICAgICAgICAgICAgIHNlZWQudXNlID0gMTMzN0wsCiAgICAgICAgICAgICAgICAgICAgICAgcmVkdWN0aW9uLm5hbWUgPSBwYXN0ZTAoIlJOQV9wY2FfIiwgbmRpbXMsICJfdW1hcCIpKQpgYGAKCldlIGNhbiB2aXN1YWxpemUgdGhlIHR3byByZXByZXNlbnRhdGlvbnMgOgoKYGBge3Igc2VlX3VtYXBfdHNuZTIsIGZpZy53aWR0aCA9IDgsIGZpZy5oZWlnaHQgPSA0LCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KdHNuZSA9IFNldXJhdDo6RGltUGxvdChzb2JqLCBncm91cC5ieSA9ICJwcm9qZWN0X25hbWUiLAogICAgICAgICAgICAgICAgICAgICAgIHJlZHVjdGlvbiA9IHBhc3RlMCgiUk5BX3BjYV8iLCBuZGltcywgIl90c25lIikpICsKICBnZ3Bsb3QyOjpzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gc2FtcGxlX2luZm8kY29sb3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNhbXBsZV9pbmZvJHByb2plY3RfbmFtZSkgKwogIFNldXJhdDo6Tm9BeGVzKCkgKyBnZ3Bsb3QyOjpnZ3RpdGxlKCJQQ0EgLSB0U05FIikgKwogIGdncGxvdDI6OnRoZW1lKGFzcGVjdC5yYXRpbyA9IDEsCiAgICAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksCiAgICAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKdW1hcCA9IFNldXJhdDo6RGltUGxvdChzb2JqLCBncm91cC5ieSA9ICJwcm9qZWN0X25hbWUiLAogICAgICAgICAgICAgICAgICAgICAgIHJlZHVjdGlvbiA9IHBhc3RlMCgiUk5BX3BjYV8iLCBuZGltcywgIl91bWFwIikpICsKICBnZ3Bsb3QyOjpzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gc2FtcGxlX2luZm8kY29sb3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNhbXBsZV9pbmZvJHByb2plY3RfbmFtZSkgKwogIFNldXJhdDo6Tm9BeGVzKCkgKyBnZ3Bsb3QyOjpnZ3RpdGxlKCJQQ0EgLSBVTUFQIikgKwogIGdncGxvdDI6OnRoZW1lKGFzcGVjdC5yYXRpbyA9IDEsCiAgICAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpCgp0c25lIHwgdW1hcApgYGAKCgojIyMgSGFybW9ueQoKV2UgcmVtb3ZlIGJhdGNoLWVmZmVjdCB1c2luZyBIYXJtb255IDoKCmBgYHtyIGhhcm1vbnksIGZpZy53aWR0aCA9IDgsIGZpZy5oZWlnaHQgPSA1fQpgJXx8JWAgPSBmdW5jdGlvbihsaHMsIHJocykgewogIGlmICghaXMubnVsbCh4ID0gbGhzKSkgewogICAgcmV0dXJuKGxocykKICB9IGVsc2UgewogICAgcmV0dXJuKHJocykKICB9Cn0KCnNldC5zZWVkKDEzMzdMKQpzb2JqID0gaGFybW9ueTo6UnVuSGFybW9ueShvYmplY3QgPSBzb2JqLAogICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cC5ieS52YXJzID0gInByb2plY3RfbmFtZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3RfY29udmVyZ2VuY2UgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICByZWR1Y3Rpb24gPSAiUk5BX3BjYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzc2F5LnVzZSA9ICJSTkEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICByZWR1Y3Rpb24uc2F2ZSA9ICJoYXJtb255IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4Lml0ZXIuaGFybW9ueSA9IDIwLAogICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9qZWN0LmRpbSA9IEZBTFNFKQpgYGAKCkZyb20gdGhpcyBiYXRjaC1lZmZlY3QgcmVtb3ZlZCBwcm9qZWN0aW9uLCB3ZSBnZW5lcmF0ZSBhIHRTTkUgYW5kIGEgVU1BUC4KCmBgYHtyIGhhcm1vbnlfdHNuZV91bWFwLCBmaWcud2lkdGggPSAxMiwgZmlnLmhlaWdodCA9IDEyfQpzb2JqID0gU2V1cmF0OjpSdW5VTUFQKHNvYmosIAogICAgICAgICAgICAgICAgICAgICAgIHNlZWQudXNlID0gMTMzN0wsCiAgICAgICAgICAgICAgICAgICAgICAgZGltcyA9IDE6bmRpbXMsCiAgICAgICAgICAgICAgICAgICAgICAgcmVkdWN0aW9uID0gImhhcm1vbnkiLAogICAgICAgICAgICAgICAgICAgICAgIHJlZHVjdGlvbi5uYW1lID0gcGFzdGUwKCJoYXJtb255XyIsIG5kaW1zLCAiX3VtYXAiKSwKICAgICAgICAgICAgICAgICAgICAgICByZWR1Y3Rpb24ua2V5ID0gcGFzdGUwKCJoYXJtb255XyIsIG5kaW1zLCAidW1hcF8iKSkKc29iaiA9IFNldXJhdDo6UnVuVFNORShzb2JqLAogICAgICAgICAgICAgICAgICAgICAgIGRpbXMgPSAxOm5kaW1zLAogICAgICAgICAgICAgICAgICAgICAgIHNlZWQudXNlID0gMTMzN0wsCiAgICAgICAgICAgICAgICAgICAgICAgcmVkdWN0aW9uID0gImhhcm1vbnkiLAogICAgICAgICAgICAgICAgICAgICAgIHJlZHVjdGlvbi5uYW1lID0gcGFzdGUwKCJoYXJtb255XyIsIG5kaW1zLCAiX3RzbmUiKSwKICAgICAgICAgICAgICAgICAgICAgICByZWR1Y3Rpb24ua2V5ID0gcGFzdGUwKCJoYXJtb255IiwgbmRpbXMsICJ0c25lXyIpKQpgYGAKClRoZXNlIGFyZSB0aGUgY29ycmVjdGVkIFVNQVAgYW5kIHRTTkUgOgoKYGBge3Igc2VlX3VtYXBfdHNuZV9oYXJtb255MSwgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDQsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQp0c25lID0gU2V1cmF0OjpEaW1QbG90KHNvYmosIGdyb3VwLmJ5ID0gInByb2plY3RfbmFtZSIsCiAgICAgICAgICAgICAgICAgICAgICAgcmVkdWN0aW9uID0gcGFzdGUwKCJoYXJtb255XyIsIG5kaW1zLCAiX3RzbmUiKSkgKwogIGdncGxvdDI6OnNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBzYW1wbGVfaW5mbyRjb2xvciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2FtcGxlX2luZm8kcHJvamVjdF9uYW1lKSArCiAgU2V1cmF0OjpOb0F4ZXMoKSArIGdncGxvdDI6OmdndGl0bGUoIlBDQSAtIGhhcm1vbnkgLSB0U05FIikgKwogIGdncGxvdDI6OnRoZW1lKGFzcGVjdC5yYXRpbyA9IDEsCiAgICAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksCiAgICAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKdW1hcCA9IFNldXJhdDo6RGltUGxvdChzb2JqLCBncm91cC5ieSA9ICJwcm9qZWN0X25hbWUiLAogICAgICAgICAgICAgICAgICAgICAgIHJlZHVjdGlvbiA9IHBhc3RlMCgiaGFybW9ueV8iLCBuZGltcywgIl91bWFwIikpICsKICBnZ3Bsb3QyOjpzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gc2FtcGxlX2luZm8kY29sb3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNhbXBsZV9pbmZvJHByb2plY3RfbmFtZSkgKwogIFNldXJhdDo6Tm9BeGVzKCkgKyBnZ3Bsb3QyOjpnZ3RpdGxlKCJQQ0EgLSBoYXJtb255IC0gVU1BUCIpICsKICBnZ3Bsb3QyOjp0aGVtZShhc3BlY3QucmF0aW8gPSAxLAogICAgICAgICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQoKdHNuZSB8IHVtYXAKYGBgCgoKIyMjIERpZmZ1c2lvbiBtYXAKCldlIGdlbmVyYXRlIGEgZGlmZnVzaW9uIG1hcCBmcm9tIHRoZSBiYXRjaC1lZmZlY3QgY29ycmVjdGVkIHNwYWNlIDoKCmBgYHtyIGRpZmZ1c2lvbl9tYXAsIGZpZy53aWR0aCA9IDgsIGZpZy5oZWlnaHQgPSA4fQpzb2JqID0gYXF1YXJpdXM6OnJ1bl9kaWZmdXNpb25fbWFwKHNvYmogPSBzb2JqLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlucHV0ID0gImhhcm1vbnkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlZWQgPSAxMzM3TCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXJib3NlID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuX2VpZ3MgPSA1MCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdXBwcmVzc19kcHQgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybl9kbSA9IEZBTFNFKQoKZG1fbmFtZSA9IHBhc3RlMCgiaGFybW9ueV9kbSIpCgpTZXVyYXQ6OkRpbVBsb3Qoc29iaiwgcmVkdWN0aW9uID0gZG1fbmFtZSwKICAgICAgICAgICAgICAgIGdyb3VwLmJ5ID0gImNlbGxfdHlwZSIsIGNvbHMgPSBjb2xvcl9tYXJrZXJzKSArCiAgZ2dwbG90Mjo6bGFicyh0aXRsZSA9IGRtX25hbWUpICsKICBnZ3Bsb3QyOjp0aGVtZShhc3BlY3QucmF0aW8gPSAxLAogICAgICAgICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSArCiAgU2V1cmF0OjpOb0F4ZXMoKQpgYGAKCldlIGdlbmVyYXRlIGEgVU1BUCBmcm9tIHRoZSBkaWZmdXNpb24gbWFwIDoKCmBgYHtyIGRtX3VtYXAsIGZpZy53aWR0aCA9IDgsIGZpZy5oZWlnaHQgPSA4fQp1bWFwX2RtX2RpbXMgPSA1CnVtYXBfbmFtZSA9IHBhc3RlMChkbV9uYW1lLCAiXyIsIHVtYXBfZG1fZGltcywgIl91bWFwIikKCnNvYmogPSBTZXVyYXQ6OlJ1blVNQVAoc29iaiwgcmVkdWN0aW9uID0gZG1fbmFtZSwKICAgICAgICAgICAgICAgICAgICAgICBkaW1zID0gMTp1bWFwX2RtX2RpbXMsCiAgICAgICAgICAgICAgICAgICAgICAgcmVkdWN0aW9uLm5hbWUgPSB1bWFwX25hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZSA9IFRSVUUsIHNlZWQudXNlID0gMTMzN0wpCgpTZXVyYXQ6OkRpbVBsb3Qoc29iaiwgcmVkdWN0aW9uID0gdW1hcF9uYW1lLAogICAgICAgICAgICAgICAgZ3JvdXAuYnkgPSAiY2VsbF90eXBlIiwgY29scyA9IGNvbG9yX21hcmtlcnMpICsKICBnZ3Bsb3QyOjpsYWJzKHRpdGxlID0gdW1hcF9uYW1lKSArCiAgZ2dwbG90Mjo6dGhlbWUoYXNwZWN0LnJhdGlvID0gMSwKICAgICAgICAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKwogIFNldXJhdDo6Tm9BeGVzKCkKYGBgCgpXZSB3aWxsIGtlZXAgdGhlIFVNQVAgZnJvbSBETSA6CgpgYGB7ciBzZXRfbmFtZTJEfQpyZWR1Y3Rpb24gPSAiaGFybW9ueSIKbmFtZTJEID0gdW1hcF9uYW1lCmBgYAoKIyMgQ2x1c3RlcmluZwoKV2UgZ2VuZXJhdGUgYSBjbHVzdGVyaW5nIDoKCmBgYHtyIGNsdXN0ZXJpbmcyLCBmaWcud2lkdGggPSA2LCBmaWcuaGVpZ2h0ID0gNH0Kc29iaiA9IFNldXJhdDo6RmluZE5laWdoYm9ycyhzb2JqLCByZWR1Y3Rpb24gPSByZWR1Y3Rpb24sIGRpbXMgPSAxOm5kaW1zKQpzb2JqID0gU2V1cmF0OjpGaW5kQ2x1c3RlcnMoc29iaiwgcmVzb2x1dGlvbiA9IDAuNSkKCmRpbXBsb3RfY2x1c3RlcnMgPSBTZXVyYXQ6OkRpbVBsb3Qoc29iaiwgcmVkdWN0aW9uID0gbmFtZTJELCBsYWJlbCA9IFRSVUUpICsKICBTZXVyYXQ6Ok5vQXhlcygpICsKICBnZ3Bsb3QyOjp0aGVtZShhc3BlY3QucmF0aW8gPSAxKQpkaW1wbG90X2NsdXN0ZXJzCmBgYAoKCiMgVmlzdWFsaXphdGlvbgoKV2UgY2FuIHJlcHJlc2VudCB0aGUgNCBxdWFsaXR5IG1ldHJpY3MgOgoKYGBge3IgcWNfcGxvdCwgZmlnLndpZHRoID0gMTIsIGZpZy5oZWlnaHQgPSAzfQpwbG90X2xpc3QgPSBTZXVyYXQ6OkZlYXR1cmVQbG90KHNvYmosIHJlZHVjdGlvbiA9IG5hbWUyRCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21iaW5lID0gRkFMU0UsIHB0LnNpemUgPSAwLjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmVhdHVyZXMgPSBjKCJwZXJjZW50Lm10IiwgInBlcmNlbnQucmIiLCAibkZlYXR1cmVfUk5BIiwgImxvZ19uQ291bnRfUk5BIikpCnBsb3RfbGlzdCA9IGxhcHBseShwbG90X2xpc3QsIEZVTiA9IGZ1bmN0aW9uKG9uZV9wbG90KSB7CiAgb25lX3Bsb3QgKwogICAgU2V1cmF0OjpOb0F4ZXMoKSArCiAgICBnZ3Bsb3QyOjpzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gYXF1YXJpdXM6Ojpjb2xvcl9nZW5lKSArCiAgICBnZ3Bsb3QyOjp0aGVtZShhc3BlY3QucmF0aW8gPSAxKQp9KQoKcGF0Y2h3b3JrOjp3cmFwX3Bsb3RzKHBsb3RfbGlzdCwgbnJvdyA9IDEpCmBgYAoKCldlIGNhbiB2aXN1YWxpemUgdGhlIHR3byBiYXRjaC1lZmZlY3QgY29ycmVjdGVkIHJlcHJlc2VudGF0aW9ucyA6CgpgYGB7ciBzZWVfdW1hcF90c25lX2FsbCwgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDgsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQpwbG90X2xpc3QgPSBsYXBwbHkoYyhwYXN0ZTAoImhhcm1vbnlfIiwgbmRpbXMsICJfdHNuZSIpLAogICAgICAgICAgICAgICAgICAgICBwYXN0ZTAoImhhcm1vbnlfIiwgbmRpbXMsICJfdW1hcCIpLAogICAgICAgICAgICAgICAgICAgICBkbV9uYW1lLCB1bWFwX25hbWUpLAogICAgICAgICAgICAgICAgICAgRlVOID0gZnVuY3Rpb24ob25lX3Byb2opIHsKICAgICAgICAgICAgICAgICAgICAgICBTZXVyYXQ6OkRpbVBsb3Qoc29iaiwgZ3JvdXAuYnkgPSAicHJvamVjdF9uYW1lIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVkdWN0aW9uID0gb25lX3Byb2opICsKICAgICAgICAgICAgICAgICAgICAgICAgIGdncGxvdDI6OnNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBzYW1wbGVfaW5mbyRjb2xvciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzYW1wbGVfaW5mbyRwcm9qZWN0X25hbWUpICsKICAgICAgICAgICAgICAgICAgICAgICAgIFNldXJhdDo6Tm9BeGVzKCkgKyBnZ3Bsb3QyOjpnZ3RpdGxlKG9uZV9wcm9qKSArCiAgICAgICAgICAgICAgICAgICAgICAgICBnZ3Bsb3QyOjp0aGVtZShhc3BlY3QucmF0aW8gPSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCiAgICAgICAgICAgICAgICAgICAgIH0pCgpwYXRjaHdvcms6OndyYXBfcGxvdHMocGxvdF9saXN0LCBuY29sID0gMikKYGBgCgpTYW1lIGZpZ3VyZSBjb2xvcmVkIGJ5IGNlbGwgdHlwZSA6CgpgYGB7ciBzZWVfdW1hcF90c25lX2FsbF9jZWxsX3R5cGUsIGZpZy53aWR0aCA9IDgsIGZpZy5oZWlnaHQgPSA4LCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KcGxvdF9saXN0ID0gbGFwcGx5KGMocGFzdGUwKCJoYXJtb255XyIsIG5kaW1zLCAiX3RzbmUiKSwKICAgICAgICAgICAgICAgICAgICAgcGFzdGUwKCJoYXJtb255XyIsIG5kaW1zLCAiX3VtYXAiKSwKICAgICAgICAgICAgICAgICAgICAgZG1fbmFtZSwgdW1hcF9uYW1lKSwKICAgICAgICAgICAgICAgICAgIEZVTiA9IGZ1bmN0aW9uKG9uZV9wcm9qKSB7CiAgICAgICAgICAgICAgICAgICAgICAgU2V1cmF0OjpEaW1QbG90KHNvYmosIGdyb3VwLmJ5ID0gImNlbGxfdHlwZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZHVjdGlvbiA9IG9uZV9wcm9qLCBjb2xzID0gY29sb3JfbWFya2VycykgKwogICAgICAgICAgICAgICAgICAgICAgICAgU2V1cmF0OjpOb0F4ZXMoKSArIGdncGxvdDI6OmdndGl0bGUob25lX3Byb2opICsKICAgICAgICAgICAgICAgICAgICAgICAgIGdncGxvdDI6OnRoZW1lKGFzcGVjdC5yYXRpbyA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKICAgICAgICAgICAgICAgICAgICAgfSkKCnBhdGNod29yazo6d3JhcF9wbG90cyhwbG90X2xpc3QsIG5jb2wgPSAyKQpgYGAKClNhbWUgZmlndXJlIGNvbG9yZWQgYnkgY2x1c3RlcnMgOgoKYGBge3Igc2VlX3VtYXBfdHNuZV9hbGxfY2x1c3RlcnMsIGZpZy53aWR0aCA9IDgsIGZpZy5oZWlnaHQgPSA4LCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KcGxvdF9saXN0ID0gbGFwcGx5KGMocGFzdGUwKCJoYXJtb255XyIsIG5kaW1zLCAiX3RzbmUiKSwKICAgICAgICAgICAgICAgICAgICAgcGFzdGUwKCJoYXJtb255XyIsIG5kaW1zLCAiX3VtYXAiKSwKICAgICAgICAgICAgICAgICAgICAgZG1fbmFtZSwgdW1hcF9uYW1lKSwKICAgICAgICAgICAgICAgICAgIEZVTiA9IGZ1bmN0aW9uKG9uZV9wcm9qKSB7CiAgICAgICAgICAgICAgICAgICAgICAgU2V1cmF0OjpEaW1QbG90KHNvYmosIGdyb3VwLmJ5ID0gInNldXJhdF9jbHVzdGVycyIsIGxhYmVsID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVkdWN0aW9uID0gb25lX3Byb2opICsKICAgICAgICAgICAgICAgICAgICAgICAgIFNldXJhdDo6Tm9BeGVzKCkgKyBnZ3Bsb3QyOjpnZ3RpdGxlKG9uZV9wcm9qKSArCiAgICAgICAgICAgICAgICAgICAgICAgICBnZ3Bsb3QyOjp0aGVtZShhc3BlY3QucmF0aW8gPSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCiAgICAgICAgICAgICAgICAgICAgIH0pCgpwYXRjaHdvcms6OndyYXBfcGxvdHMocGxvdF9saXN0LCBuY29sID0gMikKYGBgCgojIFNhdmUKCldlIHNhdmUgdGhlIFNldXJhdCBvYmplY3QgOgoKYGBge3Igc2F2ZV9zb2JqfQpzYXZlUkRTKHNvYmosIGZpbGUgPSBwYXN0ZTAob3V0X2RpciwgIi8iLCBzYXZlX25hbWUsICJfc29iai5yZHMiKSkKYGBgCgoKIyBSIFNlc3Npb24KCmBgYHtyIHNlc3Npb25pbmZvLCBlY2hvID0gRkFMU0UsIGZvbGRfb3V0cHV0ID0gVFJVRX0Kc2Vzc2lvbkluZm8oKQpgYGAKCg==